# CSS 属性值的计算过程
# CSS 属性值计算
CSS 中,每一个属性最终都要计算出最终的值,即使我们没有设置这个属性值,它依然是拥有值的。
比如我们对于一个 div,只设置宽高和背景颜色:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.main{
width: 100px;
height: 100px;
background-color: #995959;
}
</style>
</head>
<body>
<div class="main"></div>
</body>
</html>
我们在控制台中的 computed 中查看其最终计算出的样式:
可以看到,除了我们设置的属性值,div 依然具有其他很多属性值。实际上,这个 div 的每一个 CSS 属性都是有值的,这些值都是通过一系列的计算,被计算出来的。
CSS 属性的计算,分为两步:
- 层叠
- 继承和默认值
# 层叠
层叠规则,是用来解决样式表中声明值之间冲突的问题。当样式表的声明值之间有冲突时,就会采用层叠规则来计算属性值。
CSS 是 Cascading Style Sheets 的缩写,这暗示**层叠(cascade)**的概念是很重要的。
在最基本的层面上,它表明 CSS 规则的顺序很重要,但它比那更复杂。
我们来看 W3C (opens new window) 对层叠的定义:
The cascade takes an unordered list of declared values for a given property on a given element, sorts them by their declaration’s precedence as determined below, and outputs a single cascaded value.
大意是:该层叠将获取给定元素上给定属性的声明值的无序列表,按声明的优先级对它们进行排序,并输出单个层叠值。
CSS 层叠是一种算法,浏览器通过它来决定将哪些 CSS 样式规则应用到一个元素上。
什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的,前面的的一种会否决后一种):
- 来源和重要性(Importance)
- 专用性(Specificity)
- 源代码次序(Source order)
# 来源和重要性
# 来源
CSS 样式的声明值来源主要有三个地方:
- 作者样式表(Author Stylesheet):前端开发人员编写的样式表,这也是我们能够控制元素样式的唯一方式。
- 用户样式表(User Stylesheet):浏览器用户自己定义的样式表,每个用户都可以定义自己的样式表,用于覆盖开发人员编写的样式表,以获得定制化的体验。
- 用户代理样式表(User Agent Stylesheet):浏览器自带的一组 CSS 样式,其实就是浏览器的默认样式表。
不同的样式表的权重不同,默认情况下,作者样式表 > 用户样式表 > 用户代理样式表
此时你可能就会有疑问了,用户样式表不是用来覆盖开发人员的作者样式表的吗?结果用户样式表的权重比开发人员样式表的权重还低,这怎么覆盖呢?
别急,这就要提到重要性这个概念了。
# 重要性
所谓的重要性,即 !important。当在一个样式声明中使用一个 !important 规则时,此声明将覆盖任何其他声明。!important 与优先级无关,但它与最终的结果直接相关。
当多个样式表中同时使用了 !important 时,其优先级顺序为:
用户代理样式表的 !important > 用户样式表的 !important > 作者样式表的 !important
可以发现,和没有 !important 的层叠顺序完全相反。
# 层叠顺序
在执行层叠算法时,可以根据来源和重要性划分出 6 个层叠层:
首先过滤来着不同样式表的所以样式规则,保留要应用到元素上的那些规则
按照来源和重要性对这些规则进行排序,重要性规则(1-6 升序):
来源 重要程度 1 用户代理 普通 2 用户 普通 3 页面作者 普通 4 页面作者 !important5 用户 !important6 用户代理 !important如果说层叠层中有多个样式规则,则优先级高者胜出
层的优先权始终高于选择器的优先级。具有优先权的层中的样式“胜出”于具有较低优先权的层。输掉的层中选择器的优先级是无关紧要的。在层内竞争的属性值的优先级仍然会受到注意,但是在层之间没有优先级的问题,因为每个属性对应的最高优先权层才会被考虑。
# 专用性(优先级)
CSS 优先级的英文原词为 Specificity,直译过来是 “独特性,具体性” 的意思,也可以理解为专用性,MDN 翻译为 优先级。所谓专用性,其实就是衡量选择器的具体程度的一种办法,或者说,衡量一个选择器能匹配多少元素。
如果一个选择器能匹配的元素较多,那么我们就可以说他的专用性较低,反之则较高。
一般来说,元素选择器可匹配到的元素最多,所以其专用性最低,也就是优先级最低。类选择器的专用性高于元素选择器,而 ID 选择器又高于类选择器,所以,选择器的优先级顺序为(1-3 升序):
- 元素选择器、伪元素选择器
- 类选择器、伪类选择器、属性选择器
- ID 选择器
需要注意的是:通配符选择器(*)、关系选择器(>、+)对优先级没有任何影响
计算优先级的方式采用一个四位数字:
- 千位:当出现行内样式(style 属性)时,千位加 1
- 百位:每出现一个 ID 选择器时,百位加 1
- 十位:每出现一个类选择器、伪类选择器、属性选择器时,十位加 1
- 个位:每出现一个元素选择器、伪元素选择器时,个位加一
最后计算出数字,数字大者优先级高。
需要格外注意,这个数字并不是十进制数字,不能进位。也就是说,即使百分位累计到 10,也不能向千分位进位。另外,只要高位上有值,无论多少,一定高于低位。
举例来说:
1 0 0 0 是大于 0 10000 0 0 的,即使后者的百分位高达 10000
无论累积多少低级选择器,其优先级也无法高于高级别的选择器。
# 源代码次序
当选择器优先级仍然相等时,根据规则在源代码中的次序来确定使用哪条规则。
在源代码中靠后书写的样式规则的次序高于靠前书写的规则。
p {
color: red;
}
p {
color: blue;
}
一般我们习惯性的会说:靠后的样式会覆盖靠前的样式规则,但这样说其实是不准确的,两个样式其实都会被应用到该元素中,只不过靠前的样式规则被靠后的规则层叠掉了而已。
打开浏览器控制台,我们可以看到 red 规则仍然存在,不过被划上了横线,也就意味该样式未被采用:
# 继承和默认值
当属性没有声明值时,会采取继承和默认值的方式计算属性值。
在 CSS 中,每个属性都具有一个初始值,其实也就是 CSS 属性的默认值。在 CSS 规范中,都对每个属性的初始值做出了相关的定义。比如text-align 的初始值是 left,display 的初始值是 inline。
另外,每个 CSS 属性在定义时都指出了这个属性是默认继承的还是默认不继承的,当元素的一个继承属性没有指定值时,则取父元素的同属性的值。
继承有四种方式,以下是常用的两种
# initial
如果层叠值是
initial关键词,则属性的初始值将成为其指定值
也就是说,如果我们显式声明一个属性为 initial,那么这个值就会取 CSS 的默认值。
# inherit
如果层叠值是
initial关键词,无论该属性是否为可继承属性,都会强制该属性继承父元素相同的属性值。
# 总结
- 收集所有样式表中的样式规则
- 根据来源(样式表)和重要性确定层叠层的顺序
- 若层叠顺序相同,则比较优先级(专用性),优先级高的样式规则会层叠掉优先级低的规则
- 若没有声明值,或声明了使用继承/默认值,则采用继承或默认值。
# 推荐阅读
← WebView 入门 浏览器渲染原理 →